package conservare.boleto;

import java.text.DecimalFormat;
import java.text.SimpleDateFormat;

import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.servlet.ServletContext;

import org.jrimum.bopepo.view.BoletoViewer;
import org.jrimum.domkee.comum.pessoa.endereco.CEP;
import org.jrimum.domkee.comum.pessoa.endereco.Endereco;
import org.jrimum.domkee.comum.pessoa.endereco.UnidadeFederativa;
import org.jrimum.domkee.comum.pessoa.id.cprf.CPF;
import org.jrimum.domkee.financeiro.banco.Banco;
import org.jrimum.domkee.financeiro.banco.febraban.Agencia;
import org.jrimum.domkee.financeiro.banco.febraban.Carteira;
import org.jrimum.domkee.financeiro.banco.febraban.Cedente;
import org.jrimum.domkee.financeiro.banco.febraban.ContaBancaria;
import org.jrimum.domkee.financeiro.banco.febraban.Modalidade;
import org.jrimum.domkee.financeiro.banco.febraban.NumeroDaConta;
import org.jrimum.domkee.financeiro.banco.febraban.Sacado;
import org.jrimum.domkee.financeiro.banco.febraban.SacadorAvalista;
import org.jrimum.domkee.financeiro.banco.febraban.TipoDeMoeda;
import org.jrimum.domkee.financeiro.banco.febraban.TipoDeTitulo;
import org.jrimum.domkee.financeiro.banco.febraban.Titulo;
import org.jrimum.domkee.financeiro.banco.febraban.Titulo.Aceite;
import org.jrimum.utilix.text.DateFormat;

import conservare.modelo.banco.CarteiraBoleto;
import conservare.modelo.boleto.BoletoEmitido;
import conservare.util.StringUtil;

public abstract class GeradorBoleto {
	
	protected BoletoEmitido infoBoleto;
	protected CarteiraBoleto carteiraBoleto;
	protected Titulo titulo;
	
	
	public GeradorBoleto(){}
	
	public GeradorBoleto(BoletoEmitido infoBoleto, conservare.modelo.banco.CarteiraBoleto carteiraBoleto) {
		this.infoBoleto = infoBoleto;
		this.carteiraBoleto = carteiraBoleto;
		
	}

	
	protected abstract Banco criarBanco();
	protected abstract Carteira getBopepoCarteira();
	protected abstract Modalidade getBopepoModalidadeConta();
	protected abstract String getNumeroDoDocumento();
	protected abstract String getSequencialNossoNumero();
	protected abstract String getNossoNumero();
	public abstract String getNossoNumeroParaExibicao();
	protected abstract String calculaDigitoNossoNumero(String nossoNumero);
	protected abstract String getDescricaoCarteiraParaExibicao();
	
	
	
	public BoletoViewer  executar(){
		
		this.titulo = montaTitulo();
		org.jrimum.bopepo.Boleto bopepoBoleto = montaBoleto();
		
		ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
		ServletContext context = (ServletContext) externalContext.getContext();
		String caminhoArquivoTemplateBoletoPdf = context.getRealPath("WEB-INF/templatepdf/BoletoTemplateSemSacadorAvalista_HOMOLOGADO_CAIXA.pdf");
		
		BoletoViewer boletoViewer = new BoletoViewer(bopepoBoleto, caminhoArquivoTemplateBoletoPdf);
		
		return boletoViewer;
		
	}
	
	
	protected Titulo montaTitulo(){
		
		
		/*
		 *  CEDENTE
		 */
		
		Cedente cedente = new Cedente(infoBoleto.getNomeCedente(),infoBoleto.getNumeroCpfCnpjCedente());
		
		
		
		/*
		 *  CONTA BANCARIA DO CEDENTE
		 */
        
		Banco banco = criarBanco();
        ContaBancaria contaBancaria = new ContaBancaria(banco);
		contaBancaria.setNumeroDaConta(getNumeroDaContaCedente());
		contaBancaria.setCarteira(getBopepoCarteira());
		contaBancaria.setModalidade(getBopepoModalidadeConta());
		contaBancaria.setAgencia(getBopepoAgencia()); 
		
		cedente.addContaBancaria(contaBancaria);
		
		
		/*
		 * INFORMANDO DADOS SOBRE O SACADO.
		 */

		Sacado sacado = new Sacado(infoBoleto.getNomeDoSacado().toUpperCase());
        
		
        // Informando o endereço do sacado.
        Endereco enderecoSac = new Endereco();
        if(infoBoleto.getEnderecoDoSacado().getUf().getSiglaUF().equals("MG")){
        	enderecoSac.setUF(UnidadeFederativa.MG);
        }
        enderecoSac.setLocalidade(infoBoleto.getEnderecoDoSacado().getMunicipio().toUpperCase());
        enderecoSac.setCep(new CEP(infoBoleto.getEnderecoDoSacado().getCep()));
        enderecoSac.setBairro(infoBoleto.getEnderecoDoSacado().getBairro().toUpperCase());
        enderecoSac.setLogradouro(infoBoleto.getEnderecoDoSacado().getTipoLogradouro().getDescricao().toUpperCase() + " " + infoBoleto.getEnderecoDoSacado().getLogradouro().toUpperCase());
        enderecoSac.setNumero(infoBoleto.getEnderecoDoSacado().getNumero() != null && infoBoleto.getEnderecoDoSacado().getNumero() > 0 ? infoBoleto.getEnderecoDoSacado().getNumero().toString() : "");
        enderecoSac.setComplemento(infoBoleto.getEnderecoDoSacado().getComplemento() != null && !infoBoleto.getEnderecoDoSacado().getComplemento().isEmpty() ? infoBoleto.getEnderecoDoSacado().getComplemento().toUpperCase() : "");
        
        sacado.addEndereco(enderecoSac);
        
        
        /*
         *  SACADOR AVALISTA
         */
        
        
        SacadorAvalista sacadorAval = new SacadorAvalista(infoBoleto.getNomeDoSacadorAvalista().toUpperCase());
        
        
		sacadorAval.setCPRF(new CPF(infoBoleto.getNumeroCpfCnpjDoSacadorAvalista()));
		
        // Informando o endereço do sacador avalista.
        Endereco EnderecoSacAval = new Endereco();
        if(infoBoleto.getContaAReceber().getContrato().getContratante().getEndereco().getUf().getSiglaUF().equals("MG")){
        	EnderecoSacAval.setUF(UnidadeFederativa.MG);
        }
        EnderecoSacAval.setLocalidade(infoBoleto.getEnderecoDoSacadorAvalista().getMunicipio().toUpperCase());
        EnderecoSacAval.setCep(new CEP(infoBoleto.getEnderecoDoSacadorAvalista().getCep()));
        EnderecoSacAval.setBairro(infoBoleto.getEnderecoDoSacadorAvalista().getBairro().toUpperCase());
        EnderecoSacAval.setLogradouro(infoBoleto.getEnderecoDoSacadorAvalista().getTipoLogradouro().getDescricao().toUpperCase() + " " + infoBoleto.getContaAReceber().getContrato().getContratante().getEndereco().getLogradouro().toUpperCase());
        EnderecoSacAval.setNumero(infoBoleto.getEnderecoDoSacadorAvalista().getNumero() != null && infoBoleto.getContaAReceber().getContrato().getContratante().getEndereco().getNumero() > 0 ? infoBoleto.getEnderecoDoSacadorAvalista().getNumero().toString() : "");
        EnderecoSacAval.setComplemento(infoBoleto.getEnderecoDoSacadorAvalista().getComplemento() != null && !infoBoleto.getEnderecoDoSacadorAvalista().getComplemento().isEmpty() ? infoBoleto.getEnderecoDoSacadorAvalista().getComplemento().toUpperCase() : "");
        
        sacadorAval.addEndereco(EnderecoSacAval);
        
        
		
		
		
		/*
		 *  INFORMANDO OS DADOS SOBRE O TÍTULO.
		 */
		
		Titulo titulo = new Titulo(contaBancaria, sacado, cedente, sacadorAval);
		
		
		titulo.setNumeroDoDocumento(getNumeroDoDocumento());
        titulo.setNossoNumero(getNossoNumero());
        titulo.setDigitoDoNossoNumero(calculaDigitoNossoNumero(getNossoNumero()));
        titulo.setValor(infoBoleto.getValorDoDocumento());
        titulo.setDataDoDocumento(infoBoleto.getDataDoDocumento());
        SimpleDateFormat formataData = new SimpleDateFormat("dd/MM/yyyy");  
        titulo.setDataDoVencimento(DateFormat.DDMMYYYY_B.parse(formataData.format(infoBoleto.getDataDoVencimento())));
        titulo.setTipoDeDocumento(TipoDeTitulo.DM_DUPLICATA_MERCANTIL);
        titulo.setAceite(Aceite.N);
        titulo.setTipoDeMoeda(TipoDeMoeda.REAL);
		
		
        return titulo;
	        
	}
	

	 /*
    * INFORMANDO OS DADOS SOBRE O BOLETO.
    */
	protected org.jrimum.bopepo.Boleto montaBoleto(){
		
		
       /**
		 * Parametros: Numero do cedente com 6 digitos, Digito verificador do
		 * codigo do cedente, Nosso numero
		 */
       conservare.util.CampoLivreCefSIGCB campoLivreCefSIGCB = new conservare.util.CampoLivreCefSIGCB(infoBoleto.getContaBancaria().getNumeroDoConvenio(), infoBoleto.getContaBancaria().getNumeroDoConvenioDV(), getNossoNumero());
		
       
       org.jrimum.bopepo.Boleto boleto = new org.jrimum.bopepo.Boleto(titulo, campoLivreCefSIGCB);
       
       boleto.setLocalPagamento(this.carteiraBoleto.getTextoLocalDePagamento());
       boleto.setInstrucaoAoSacado("Senhor sacado, sabemos sim que o valor cobrado não é o esperado, aproveite o DESCONTÃO!");
       
       boleto.setInstrucao2("MULTA DE R$ " + new DecimalFormat("#,##0.BoletoTemplateSemSacadorAvalista_HOMOLOGADO_CAIXA.pdfBoletoTemplateSemSacadorAvalista_HOMOLOGADO_CAIXA.pdf00").format(infoBoleto.getValorMulta().doubleValue()) + " APÓS: " +  new SimpleDateFormat("dd/MM/yyyy").format(infoBoleto.getDataDoVencimento()));
       boleto.setInstrucao3("JUROS DE R$ " + new DecimalFormat("#,##0.00").format(infoBoleto.getValorJurosMora().doubleValue()) + " AO DIA");
       boleto.setInstrucao5("NÃO RECEBER APOS " + this.carteiraBoleto.getNaoReceberAposXDias() + " DIAS DO VENCIMENTO");
       
       boleto.addTextosExtras("txtFcAgenciaCodigoCedente", getAgenciaCodigoDoCedenteParaExibicao());
       boleto.addTextosExtras("txtRsAgenciaCodigoCedente", getAgenciaCodigoDoCedenteParaExibicao()); 
       boleto.addTextosExtras("txtRsEspecieDocumento", titulo.getTipoDeDocumento().getSigla());
       boleto.addTextosExtras("txtFcNossoNumero", getNossoNumeroParaExibicao()); 
       boleto.addTextosExtras("txtRsNossoNumero", getNossoNumeroParaExibicao()); 
       boleto.addTextosExtras("txtRsEspecie", "R$"); 
       boleto.addTextosExtras("txtFcEspecie", "R$"); 
       boleto.addTextosExtras("txtRsCarteira", getDescricaoCarteiraParaExibicao());
       boleto.addTextosExtras("txtFcCarteira", getDescricaoCarteiraParaExibicao());
       if(titulo.getAceite().equals(Aceite.N)){
       	boleto.addTextosExtras("txtFcAceite", "NAO");
       }
       boleto.addTextosExtras("txtRsDataProcessamento",new SimpleDateFormat("dd/MM/yyyy").format(titulo.getDataDoDocumento()));
       boleto.addTextosExtras("txtRsDataDocumento",new SimpleDateFormat("dd/MM/yyyy").format(titulo.getDataDoDocumento()));
       boleto.addTextosExtras("txtRsSacadoCpfCnpj", titulo.getSacado().getCPRF() != null ? titulo.getSacado().getCPRF().getCodigoFormatado() : "000.000.000-00");	
       
       Endereco bopepoEnderecoSac = titulo.getSacado().getEnderecos().iterator().next();
       String rsEndSacado =  bopepoEnderecoSac.getLogradouro() + " " + bopepoEnderecoSac.getNumero();
       rsEndSacado += bopepoEnderecoSac.getComplemento() != null ? " " + bopepoEnderecoSac.getComplemento().toUpperCase() : "";
       rsEndSacado += " - " + bopepoEnderecoSac.getBairro().toUpperCase() + " - " + bopepoEnderecoSac.getLocalidade().toUpperCase();
       
       boleto.addTextosExtras("txtRsSacadoEndereco", rsEndSacado);
       boleto.addTextosExtras("txtRsSacadoUf", bopepoEnderecoSac.getUF().getSigla());
       boleto.addTextosExtras("txtRsSacadoCep", bopepoEnderecoSac.getCEP().getCep());
       
       String fcEndSacado = bopepoEnderecoSac.getLogradouro() + " " + bopepoEnderecoSac.getNumero();
       fcEndSacado += bopepoEnderecoSac.getComplemento() != null ? " " + bopepoEnderecoSac.getComplemento().toUpperCase() : "";
       fcEndSacado += " " + bopepoEnderecoSac.getBairro().toUpperCase();
       
       boleto.addTextosExtras("txtFcSacadoL1", titulo.getSacado().getNome().toUpperCase());
       boleto.addTextosExtras("txtFcSacadoL2", fcEndSacado);
       boleto.addTextosExtras("txtFcSacadoL3", bopepoEnderecoSac.getLocalidade().toUpperCase());
       boleto.addTextosExtras("txtFcSacadoCep", bopepoEnderecoSac.getCEP().getCep());
       boleto.addTextosExtras("txtFcSacadoUf", bopepoEnderecoSac.getUF().getSigla());
       boleto.addTextosExtras("txtFcSacadoCpfCnpj", titulo.getSacado().getCPRF() != null ? titulo.getSacado().getCPRF().getCodigoFormatado() : "000.000.000-00");
       
       
       
       boleto.addTextosExtras("txtRsSacadoAvalistaL1", titulo.getSacadorAvalista().getNome().toUpperCase());
       boleto.addTextosExtras("txtFcSacadoAvalistaL1", titulo.getSacadorAvalista().getNome().toUpperCase());
       boleto.addTextosExtras("txtRsSacadoAvalistaCpfCnpj", titulo.getSacadorAvalista().getCPRF().getCodigoFormatado());
       boleto.addTextosExtras("txtFcSacadoAvalistaCpfCnpj", titulo.getSacadorAvalista().getCPRF().getCodigoFormatado());
       
       DecimalFormat df = new DecimalFormat("#,###,##0.00");
       boleto.addTextosExtras("txtRsValorDocumento", df.format(titulo.getValor().doubleValue()));
       boleto.addTextosExtras("txtFcValorDocumento", df.format(titulo.getValor().doubleValue()));
       
       
       boleto.addTextosExtras("txtFcCpfCnpj", titulo.getCedente().getCPRF().getCodigoFormatado());
       boleto.addTextosExtras("txtRcCedenteEndereco", infoBoleto.getContaBancaria().getEmpresa().getEnderecoCompletoFormatadoParaUmaLinha().toUpperCase()); 
       boleto.addTextosExtras("txtFcCedenteEndereco",infoBoleto.getContaBancaria().getEmpresa().getEnderecoCompletoFormatadoParaUmaLinha().toUpperCase());
       
       
       return boleto;
       
	}
	
	/*protected Cedente getCedente(){
		
		return new Cedente(infoBoleto.getContaBancaria().getEmpresa().getNome(),infoBoleto.getContaBancaria().getEmpresa().getCpfCnpj().getNumero());
		
	}*/
	
	/*protected Sacado getSacado(){
		
		
		 * INFORMANDO DADOS SOBRE O SACADO.
		 

		Sacado sacado = new Sacado(infoBoleto.getContaAReceber().getContrato().getLocalPrestacaoServico().getDescricao().toUpperCase());
        
		
        // Informando o endereço do sacado.
        Endereco enderecoSac = new Endereco();
        if(infoBoleto.getContaAReceber().getContrato().getLocalPrestacaoServico().getEndereco().getUf().getSiglaUF().equals("MG")){
        	enderecoSac.setUF(UnidadeFederativa.MG);
        }
        enderecoSac.setLocalidade(infoBoleto.getContaAReceber().getContrato().getLocalPrestacaoServico().getEndereco().getMunicipio().toUpperCase());
        enderecoSac.setCep(new CEP(infoBoleto.getContaAReceber().getContrato().getLocalPrestacaoServico().getEndereco().getCep()));
        enderecoSac.setBairro(infoBoleto.getContaAReceber().getContrato().getLocalPrestacaoServico().getEndereco().getBairro().toUpperCase());
        enderecoSac.setLogradouro(infoBoleto.getContaAReceber().getContrato().getLocalPrestacaoServico().getEndereco().getTipoLogradouro().getDescricao().toUpperCase() + " " + infoBoleto.getContaAReceber().getContrato().getLocalPrestacaoServico().getEndereco().getLogradouro().toUpperCase());
        enderecoSac.setNumero(infoBoleto.getContaAReceber().getContrato().getLocalPrestacaoServico().getEndereco().getNumero() != null && infoBoleto.getContaAReceber().getContrato().getLocalPrestacaoServico().getEndereco().getNumero() > 0 ? infoBoleto.getContaAReceber().getContrato().getLocalPrestacaoServico().getEndereco().getNumero().toString() : "");
        enderecoSac.setComplemento(infoBoleto.getContaAReceber().getContrato().getLocalPrestacaoServico().getEndereco().getComplemento() != null && !infoBoleto.getContaAReceber().getContrato().getLocalPrestacaoServico().getEndereco().getComplemento().isEmpty() ? infoBoleto.getContaAReceber().getContrato().getLocalPrestacaoServico().getEndereco().getComplemento().toUpperCase() : "");
        
        sacado.addEndereco(enderecoSac);
		
		return sacado;
		
	}
	*/
	
/*
	protected SacadorAvalista getSacadorAvalista(){
		

        // Sacado Avalista
        
        SacadorAvalista sacadorAval = new SacadorAvalista(infoBoleto.getContaAReceber().getContrato().getContratante().getNome().toUpperCase());
        
        
		sacadorAval.setCPRF(new CPF(infoBoleto.getContaAReceber().getContrato().getContratante().getCpfCnpj().getNumero()));
		
        // Informando o endereço do sacador avalista.
        Endereco EnderecoSacAval = new Endereco();
        if(infoBoleto.getContaAReceber().getContrato().getContratante().getEndereco().getUf().getSiglaUF().equals("MG")){
        	EnderecoSacAval.setUF(UnidadeFederativa.MG);
        }
        EnderecoSacAval.setLocalidade(infoBoleto.getContaAReceber().getContrato().getContratante().getEndereco().getMunicipio().toUpperCase());
        EnderecoSacAval.setCep(new CEP(infoBoleto.getContaAReceber().getContrato().getContratante().getEndereco().getCep()));
        EnderecoSacAval.setBairro(infoBoleto.getContaAReceber().getContrato().getContratante().getEndereco().getBairro().toUpperCase());
        EnderecoSacAval.setLogradouro(infoBoleto.getContaAReceber().getContrato().getContratante().getEndereco().getTipoLogradouro().getDescricao().toUpperCase() + " " + infoBoleto.getContaAReceber().getContrato().getContratante().getEndereco().getLogradouro().toUpperCase());
        EnderecoSacAval.setNumero(infoBoleto.getContaAReceber().getContrato().getContratante().getEndereco().getNumero() != null && infoBoleto.getContaAReceber().getContrato().getContratante().getEndereco().getNumero() > 0 ? infoBoleto.getContaAReceber().getContrato().getContratante().getEndereco().getNumero().toString() : "");
        EnderecoSacAval.setComplemento(infoBoleto.getContaAReceber().getContrato().getContratante().getEndereco().getComplemento() != null && !infoBoleto.getContaAReceber().getContrato().getContratante().getEndereco().getComplemento().isEmpty() ? infoBoleto.getContaAReceber().getContrato().getContratante().getEndereco().getComplemento().toUpperCase() : "");
        
        sacadorAval.addEndereco(EnderecoSacAval);
        
        return sacadorAval;
        
	}*/
	
	
	/*protected ContaBancaria getContaBancaria(){
		

        // Informando dados sobre a conta conta bancaria do titulo.
        
        ContaBancaria contaBancaria = new ContaBancaria(criarBanco())
		contaBancaria.setNumeroDaConta(getBopepoNumeroDaConta()); 
		
		
		contaBancaria.setCarteira(getBopepoCarteira());
		contaBancaria.setModalidade(getBopepoModalidadeConta());
		contaBancaria.setAgencia(getBopepoAgencia()); 
		
        
        return contaBancaria;
	}*/

	
	protected NumeroDaConta getNumeroDaContaCedente(){
		
		String numeroDoConvenio = StringUtil.trimLeadingZeros(infoBoleto.getContaBancaria().getNumeroDoConvenio()); //remove zeros da esquerda
		String numeroDoConvenioDV = infoBoleto.getContaBancaria().getNumeroDoConvenioDV();
		return new NumeroDaConta(Integer.parseInt(numeroDoConvenio),  numeroDoConvenioDV);
		
	}
	
	
	protected Agencia getBopepoAgencia(){
		
		String numeroDaAgencia = StringUtil.trimLeadingZeros(infoBoleto.getContaBancaria().getAgencia().getNumeroDaAgencia());
		String numeroDaAgenciaDV = infoBoleto.getContaBancaria().getAgencia().getNumeroDoDV().toString();
		return new Agencia(Integer.parseInt(numeroDaAgencia), numeroDaAgenciaDV);
		
	}
	
	
	/*
	 * A área do boleto destinada a "Agência/Código do Cedente" deverá exibir a informação
	 * "Agência (com 4 dígitos, zeros a esquerda)/Conta bancária". Ex: 0057/21109-2.
	 */
	protected String getAgenciaCodigoDoCedenteParaExibicao(){
		
        String agenciaCodigoDoCedenteParaExibicao = String.format("%04d/%d-%s",
        		titulo.getContaBancaria().getAgencia().getCodigo(),
        		titulo.getContaBancaria().getNumeroDaConta().getCodigoDaConta(),
        		titulo.getContaBancaria().getNumeroDaConta().getDigitoDaConta());
        
        return agenciaCodigoDoCedenteParaExibicao;
        
	}
	
	 
	
}
